from collections import defaultdict

from django.db.models import F
import random
from .models import Appointment, Queue, Doctor, Patient, VisitDoctor
from django.utils import timezone
import datetime
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView

online_queue_number = -2
offline_queue_number = -3
# 获取当前预约时间段
def get_slot_and_day():
    current_slot = get_slot_for_current_time()
    current_day = datetime.date.today()
    # current_slot = 1
    # current_day = "2025-01-09"
    return current_slot, current_day


def generate_appointment_time(appointment_date, time_slot):
    # 定义各个时段的开始时间
    time_slots = {
        1: "09:00",  # 09:00-10:00
        2: "11:00",  # 11:00-12:00
        3: "14:00",  # 14:00-15:00
        4: "16:00",  # 16:00-17:00
    }

    # 获取时间段对应的开始时间
    time_str = time_slots.get(time_slot)

    if not time_str:
        raise ValueError("无效的时间段，必须是1, 2, 3或4")

    # 将预约日期和时间段开始时间组合成一个字符串
    appointment_datetime_str = f"{appointment_date} {time_str}"

    # 将字符串转化为 datetime 类型
    appointment_datetime = datetime.datetime.strptime(appointment_datetime_str, "%Y-%m-%d %H:%M")

    # 返回生成的预约时间
    return appointment_datetime


def get_slot_for_current_time():
    current_time = datetime.datetime.now().time()  # 获取当前时间（不包括日期）
    print('函数内', current_time)

    # 定义时段的开始时间和结束时间（每个时段的范围）
    slot_times = [
        {"slot": 1, "start": "09:00", "end": "10:59"},
        {"slot": 2, "start": "11:00", "end": "12:00"},
        {"slot": 3, "start": "14:00", "end": "15:59"},
        {"slot": 4, "start": "16:00", "end": "17:00"}
    ]

    # 将当前时间转化为字符串（只保留时分部分）
    current_time_str = current_time.strftime("%H:%M")

    # 查找当前时间所在的时段
    for slot in slot_times:
        if slot["start"] <= current_time_str < slot["end"]:
            return slot["slot"]

    return None  # 如果当前时间不在任何时段内，返回 None


class AvailableSlots(APIView):
    def get(self, request):
        # 获取传入的 doctor_id
        doctor_id = request.GET.get('doctor_id')

        # 获取当前时间，并计算接下来的三天
        current_time = timezone.now()
        today = current_time.date()
        next_three_days = [today + datetime.timedelta(days=i) for i in range(3)]

        # 定义时间段（slot）
        time_slots = {
            1: ("09:00", "10:00"),
            2: ("11:00", "12:00"),
            3: ("14:00", "15:00"),
            4: ("16:00", "17:00"),
        }

        # 查询这三天内该医生的所有预约记录
        appointments = Appointment.objects.filter(
            doctor_id=doctor_id,
            appointment_date__in=next_three_days,
            queue_number__gt=-4  # 只查询有效的预约（排队号大于等于1的）
        )

        # 统计每个日期每个时间段的已预约数量
        booked_slots = defaultdict(lambda: defaultdict(int))  # 使用defaultdict，避免KeyError

        for appointment in appointments:
            # 统计已预约的时间段
            booked_slots[appointment.appointment_date.isoformat()][appointment.time_slot] += 1

        # 计算可用的时间段（每个时间段最多10个号）
        available_slots = {}
        for date in next_three_days:
            date_str = date.isoformat()
            available_slots[date_str] = {
                slot: 10 - booked_slots[date_str].get(slot, 0) for slot in time_slots.keys()
            }

        return Response(available_slots)


class OnlineAppointment(APIView):
    def post(self, request):
        # 获取请求中的数据
        patient_id = request.data.get('patient_id')
        doctor_id = request.data.get('doctor_id')
        appointment_date = request.data.get('appointment_date')
        time_slot = request.data.get('time_slot')
        if not all([patient_id, doctor_id, appointment_date, time_slot]):
            return Response({"error": "所有字段都必须填写"}, status=status.HTTP_400_BAD_REQUEST)
        current_slot, current_day = get_slot_and_day()
        print('当前slot', current_slot)
        print('当前date', current_day)
        print('传入slot', time_slot)
        print('传入date', appointment_date)
        print('传入patient_id', patient_id)
        # 查询是否有重复预约
        if Appointment.objects.filter(
                doctor_id=doctor_id,
                patient_id=patient_id,
                appointment_date=appointment_date,
                time_slot=time_slot,
        ).exists():
            return Response({"error": "不可重复预约"}, status=status.HTTP_400_BAD_REQUEST)

        # 判断是否为现场挂号
        if str(current_day) == appointment_date and str(current_slot) == time_slot:

            # 检查该时间段是否已满
            if Appointment.objects.filter(
                    doctor_id=doctor_id,
                    appointment_date=appointment_date,
                    time_slot=current_slot,
                    status__in=['pending', 'paid']
            ).count() >= 10:
                return Response({"error": "此时段号源已满"}, status=status.HTTP_400_BAD_REQUEST)

            appointment = Appointment.objects.create(
                patient_id=patient_id,
                doctor_id=doctor_id,
                appointment_date=appointment_date,
                time_slot=time_slot,
                subject=Doctor.objects.get(id=doctor_id).subject_name,
                queue_number=offline_queue_number # 现场挂号标记为-3
                # queue_number=Appointment.objects.filter(
                #     doctor_id=doctor_id,
                #     appointment_date=appointment_date,
                #     time_slot=time_slot
                # ).count() + 1  # 直接排到最后面
            )


            return Response({"message": "现场挂号成功", "appointment_id": appointment.id}, status=status.HTTP_200_OK)
        else:

            # 检查是否已满员
            if Appointment.objects.filter(
                    doctor_id=doctor_id,
                    appointment_date=appointment_date,
                    time_slot=time_slot,
                    status__in=['pending', 'paid']
            ).count() >= 10:
                return Response({"error": "此时段号源已满"}, status=status.HTTP_400_BAD_REQUEST)

            # # 创建预约
            # appointment = Appointment.objects.create(
            #     patient_id=patient_id,
            #     doctor_id=doctor_id,
            #     appointment_date=appointment_date,
            #     time_slot=time_slot,
            #     queue_number=Appointment.objects.filter(
            #         doctor_id=doctor_id,
            #         appointment_date=appointment_date,
            #         time_slot=time_slot
            #     ).count() + 1
            # )

            # # 获取当前医生某天某时段的队列
            # current_queue_count = Appointment.objects.filter(
            #     doctor_id=doctor_id,
            #     appointment_date=appointment_date,
            #     time_slot=time_slot,
            #     queue_number__gt=0  # 只查询已排队的患者
            # ).count()
            #
            # # 判断队列的长度并决定插入位置
            # if current_queue_count <= 3:
            #     # 如果队列长度小于等于3，直接排到队列最后
            #     queue_position = current_queue_count + 1
            # elif current_queue_count <= 10:
            #     # 如果队列长度大于3且小于等于10，插入 3 到 current_queue_count 之间的随机位置
            #     queue_position = random.randint(3, current_queue_count)
            # else:
            #     # 如果队列长度大于10，插入 3 到 10 之间的随机位置
            #     queue_position = random.randint(3, 10)
            #
            # # 将队列中位置 >= queue_position 的患者位置后移
            # Appointment.objects.filter(
            #     doctor_id=doctor_id, appointment_date=appointment_date, time_slot=time_slot,
            #     queue_number__gte=queue_position
            # ).update(queue_number=F('queue_number') + 1)

            appointment = Appointment.objects.create(
                patient_id=patient_id,
                doctor_id=doctor_id,
                appointment_date=appointment_date,
                time_slot=time_slot,
                subject=Doctor.objects.get(id=doctor_id).subject_name,
                queue_number=online_queue_number # 将在线预约标记为-2
            )

            return Response({"message": "在线预约成功", "appointment_id": appointment.id}, status=status.HTTP_200_OK)


#
# class OfflineAppointment(APIView):
#     def post(self, request):
#         patient_id = request.data.get('patient_id')
#         doctor_id = request.data.get('doctor_id')
#         # time_slot = request.data.get('time_slot')  # 获取时间段
#         current_slot = get_slot_for_current_time()
#         # 获取当前日期（精确到天）
#         appointment_date = datetime.date.today()
#
#         # 检查该时间段是否已满
#         if Appointment.objects.filter(
#                 doctor_id=doctor_id,
#                 appointment_date=appointment_date,
#                 time_slot=current_slot,
#                 status__in=['pending', 'paid']
#         ).count() >= 15:
#             return Response({"error": "此时段号源已满"}, status=status.HTTP_400_BAD_REQUEST)
#
#         # 现场挂号，排到队列末尾
#         position = Queue.objects.filter(doctor_id=doctor_id).count() + 1
#
#         # 创建现场挂号记录，并填充appointment_date
#         Queue.objects.create(
#             doctor_id=doctor_id,
#             patient_id=patient_id,
#             position=position,
#             time_slot=current_slot,
#             appointment_date=appointment_date  # 自动填充当前日期
#         )
#
#         return Response({"message": "现场挂号成功，已排队"}, status=status.HTTP_201_CREATED)


# 修改支付逻辑，判断时间应该用slot进行判断
class OnlinePayment(APIView):
    def post(self, request):
        appointment_id = request.data.get('appointment_id')
        appointment = Appointment.objects.filter(id=appointment_id, status='pending').first()

        if not appointment:
            return Response({"error": "无效的预约信息或预约已完成缴费"}, status=status.HTTP_400_BAD_REQUEST)
        # FIXME
        current_time = datetime.datetime.now()
        print(current_time)
        print(generate_appointment_time(appointment.appointment_date, appointment.time_slot))
        time_difference = generate_appointment_time(appointment.appointment_date, appointment.time_slot) - current_time
        print(time_difference)
        # 计算时间差的秒数，然后转换为分钟数
        time_difference_minutes = time_difference.total_seconds() / 60
        print(time_difference_minutes)

        # 如果当前时间距离预约时间超过20分钟

        if time_difference_minutes > 20:
            return Response({"error": "您只能提前20分钟缴费"}, status=status.HTTP_403_FORBIDDEN)
        elif time_difference_minutes < -120:

            return Response({"error": "您已经错过缴费时期"}, status=status.HTTP_403_FORBIDDEN)

        else:
            # 更新状态为已缴费

            # 现场挂号，直接排到最后
            if appointment.queue_number == offline_queue_number:
                # 还有号就进行插入
                sumapp = Appointment.objects.filter(
                    doctor_id=appointment.doctor_id,
                    appointment_date=appointment.appointment_date,
                    time_slot=appointment.time_slot,
                    queue_number__gt=0  # 只查询已排队的患者
                ).count()
                if sumapp < 10:
                    appointment.queue_number = sumapp + 1
                    appointment.status = 'paid'
                    appointment.save()
                    return Response({"message": "缴费成功1,排队位置为：" + str(appointment.queue_number)},
                                    status=status.HTTP_200_OK)
                else:
                    return Response({"error": "队列已满"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            # 预约挂号插入逻辑
            elif appointment.queue_number == online_queue_number:

                # 获取当前医生某天某时段的队列
                current_queue_count = Appointment.objects.filter(
                    doctor_id=appointment.doctor_id,
                    appointment_date=appointment.appointment_date,
                    time_slot=appointment.time_slot,
                    queue_number__gt=0  # 只查询已排队的患者
                ).count()
                print("当前排队数目", current_queue_count)
                # 判断队列的长度并决定插入位置

                if current_queue_count <= 3:
                    # 如果队列长度小于等于3，直接排到队列最后
                    queue_position = current_queue_count + 1
                elif current_queue_count <= 10:
                    # 如果队列长度大于3且小于等于10，插入 3 到 current_queue_count 之间的随机位置
                    queue_position = random.randint(3, current_queue_count)
                else:
                    # 如果队列长度大于10，插入 3 到 10 之间的随机位置
                    queue_position = 10

                # 将队列中位置 >= queue_position 的患者位置后移
                Appointment.objects.filter(
                    doctor_id=appointment.doctor_id, appointment_date=appointment.appointment_date,
                    time_slot=appointment.time_slot,
                    queue_number__gte=queue_position
                ).update(queue_number=F('queue_number') + 1)
                print("应插入位置", queue_position)
                appointment.status = 'paid'
                appointment.queue_number = queue_position
                appointment.save()
            return Response({"message": "缴费成功2,排队位置为：" + str(appointment.queue_number)},
                            status=status.HTTP_200_OK)


# 查看当前队列状态
class QueueStatus(APIView):
    def get(self, request):
        doctor_id = request.GET.get('doctor_id')
        current_slot, current_day = get_slot_and_day()

        if current_slot is None:
            print('当前的slot', current_slot)  # 输出 1、2、3 或 4
            return Response({"已经下班啦"})

        # 查询排队队列
        appiontment = Appointment.objects.filter(doctor_id=doctor_id,
                                                 time_slot=current_slot,
                                                 appointment_date=current_day,
                                                 queue_number__gt=0
                                                 ).order_by('queue_number')

        # 查询医生信息
        # doctor = Doctor.objects.filter(id=doctor_id).first()
        # if not doctor:
        #     return Response({"error": "医生信息未找到"}, status=404)

        # 返回排队信息，包括患者名字和医生名字
        data = []
        for q in appiontment:
            patient = Patient.objects.filter(id=q.patient.id).first()
            if patient:
                data.append({
                    "appointment_id": q.id,
                    "patient_id": q.patient.id,
                    "queue_number": q.queue_number,
                    "patient_name": q.patient.name,
                    "doctor_name": q.doctor.doctor_name,
                    "patient_age": q.patient.age,
                    "patient_gender": q.patient.gender,

                })
            else:
                data.append({
                    "position": q.queue_number,
                    "patient_name": "未知患者",
                    "doctor_name": q.doctor.doctor_name
                })

        return Response(data)


class GetCurrentPatient(APIView):
    def get(self, request):
        appointment_id = request.GET.get('appointment_id')
        # current_slot, current_day = get_slot_and_day()
        #
        # if current_slot is None:
        #     return Response({"已经下班啦"})
        #
        # print('当前的slot', current_slot)  # 输出 1、2、3 或 4
        # 查询排队队列
        data = []
        try:
            # 获取预约记录
            appointment = Appointment.objects.get(
                id= appointment_id,
            )

            # 将预约信息加入到 data 列表
            data.append({
                "appointment_id": appointment.id,
                "patient_id": appointment.patient.id,
                "queue_number": appointment.queue_number,
                "patient_name": appointment.patient.name,
                "doctor_name": appointment.doctor.doctor_name,
                "patient_age": appointment.patient.age,
                "patient_gender": appointment.patient.gender,
            })
            return Response(data, status=status.HTTP_200_OK)

        except Appointment.DoesNotExist:
            # 处理查询不到数据的情况
            return Response({"error": "没有找到匹配的预约记录"}, status=status.HTTP_404_NOT_FOUND)


# DONE
class MyAppointment(APIView):
    def get(self, request):
        patient_id = request.GET.get('patient_id')
        appointments = Appointment.objects.filter(patient_id=patient_id, queue_number__gt=-4).order_by('created_at')
        data = []
        for appointment in appointments:
            data.append({
                "appointment_id": appointment.id,
                "appointment_date": appointment.appointment_date,
                "time_slot": appointment.time_slot,
                "status": appointment.status,
                "doctor_name": appointment.doctor.doctor_name,
                "order_money": appointment.doctor.order_money,
                'position': appointment.queue_number,
                "subject": appointment.subject
            })
        return Response(data)


class DoctorCall(APIView):
    def get(self, request):
        doctor_id = request.GET.get('doctor_id')

        # 获取当前日期和当前时间段
        current_slot, current_day = get_slot_and_day()
        # current_slot = 3

        # 获取该医生当前时间段的所有预约患者
        appointments = Appointment.objects.filter(
            doctor_id=doctor_id,
            appointment_date=current_day,
            time_slot=current_slot,
            clinc_status='InQueue'
        ).order_by('queue_number')

        # 如果没有患者排队
        if not appointments.exists():
            return Response({"message": "当前无患者排队"}, status=status.HTTP_200_OK)

        # 获取排在第一个的患者
        first_appointment = appointments.first()

        # 更新第一个患者的状态为 'Called'，并将队列号设置为 -1
        # FIXME
        # first_appointment.clinc_status = "Called"
        first_appointment.clinc_status = "Called"
        first_appointment.queue_number = -1
        first_appointment.save()

        # 更新后续患者的队列号，将其向前移动
        for appointment in appointments[0:]:
            appointment.queue_number -= 1
            appointment.save()
        return Response({"message": "已成功叫号,请" + first_appointment.patient.name + "就诊"},
                        status=status.HTTP_200_OK)


# 标记是否就诊
class DoctorDiagnosed(APIView):
    def get(self, request):
        doctor_id = request.GET.get('doctor_id')
        is_diagnosed = request.GET.get('isDiagnosed')
        current_slot, current_day = get_slot_and_day()
        if not is_diagnosed:
            appointments = Appointment.objects.filter(doctor_id=doctor_id, appointment_date=current_day,
                                                      time_slot=current_slot).order_by('queue_number')
            appointments.first().clinc_status = "Suspended"
            appointments.first().save()
        return Response({"message": "已成功就诊"},
                        status=status.HTTP_200_OK)


class CancelAppointment(APIView):
    def post(self, request):
        appointment_id = request.data.get('appointment_id')
        appointment = Appointment.objects.filter(id=appointment_id, status='pending').first()

        if not appointment:
            return Response({"error": "无效的预约信息或预约不可取消"}, status=status.HTTP_400_BAD_REQUEST)

        appointment.status = 'canceled'
        appointment.save()
        return Response({"message": "预约已取消"}, status=status.HTTP_200_OK)


class Suspend(APIView):
    def post(self, request):
        queue_id = request.data.get('queue_id')
        queue = Queue.objects.filter(id=queue_id, is_suspended=False).first()

        if not queue:
            return Response({"error": "无效的队列信息或患者已挂起"}, status=status.HTTP_400_BAD_REQUEST)

        queue.is_suspended = True
        queue.save()
        return Response({"message": "患者已挂起"}, status=status.HTTP_200_OK)


class Unsuspend(APIView):
    def post(self, request):
        queue_id = request.data.get('queue_id')
        queue = Queue.objects.filter(id=queue_id, is_suspended=True).first()

        if not queue:
            return Response({"error": "无效的挂起信息"}, status=status.HTTP_400_BAD_REQUEST)

        # 获取当前队列前 5 名的所有患者
        existing_queues = Queue.objects.filter(doctor=queue.doctor, is_suspended=False).order_by('position')[
                          :5]

        # 随机生成插入位置
        random_position = random.randint(1, min(5, existing_queues.count() + 1))

        # 调整后续患者位置
        for q in existing_queues:
            if q.position >= random_position:
                q.position += 1
                q.save()

        # 更新挂起患者的位置
        queue.is_suspended = False
        queue.position = random_position
        queue.save()

        return Response({"message": "患者已解挂并随机插入队列前 5 名"}, status=status.HTTP_200_OK)
